import hashlib
from socket import *
# socket = socket(AF_INET, SOCK_STREAM)
# socket.connect(("localhost",1234))
import optparse
import json,os,sys


STATUS_CODE={'1':"passed authenticate",
 "0":"fail",
 "200":"success",
 "253":"Wrong username or password",
 "254":"passed authenticate ",
 "250":"invalid cmd format,e.g:{'action':'get','filename':'test.py','filesize':'344'}",
 "256":"Filname doesn't exits on server",
 "257":"ready to send file",
 "500":"internet server error",
 "404":"soure not exite",
 "802":"文件不存在",
 "801":"文件已存在",
 '800':"文件存在但不完整"
}

class ClientHandler():
    def __init__(self):
        self.op = optparse.OptionParser()
        self.op.add_option("-s", "--server", dest="server")
        self.op.add_option("-P", "--port", dest="port")
        self.op.add_option("-u", "--username", dest="username")
        self.op.add_option("-p", "--password", dest="password")
        self.options,self.args = self.op.parse_args()
        self.verify_auth(self.options,self.args)
        self.make_connection()
        self.mainPath = os.path.dirname(os.path.abspath(__file__))

    def verify_auth(self,options,args):
        # server = options.server
        port = options.port
        # username = options.username
        # password = options.password
        if int(port)> 0 and int(port)< 65535:
            return True
        else:
            exit("the port is in 0-65535")

    def make_connection(self):
        self.socket = socket(AF_INET,SOCK_STREAM)
        self.socket.connect((self.options.server,int(self.options.port)))

    def interactive(self):
        if self.authenticate():
            print("begin to interactive...")
            cmd_info = input("[%s]" %self.user).strip()
            cmd_list = cmd_info.strip()
            if hasattr(self,cmd_list[0]):
                func=getattr(self,cmd_list[0])
                func(cmd_list)

    def put(self,*cmd_list):
        action,local_ptah,target_path=cmd_list
        local_ptah =os.path.join(self.mainPath,local_ptah)
        file_name=os.path.basename(local_ptah)
        file_size=os.stat(local_ptah).st_size

        data={"action":"put",
              "file_name":file_name,
              "file_size":file_size,
              "target_path":target_path
        }
        self.socket.sendall(json.dumps(data).encode("utf-8"))
        is_exits = self.socket.recv(1024).decode("utf-8")
        has_sent=0
        if is_exits=="800":
            '''文件存在不完整'''
            chocie=input("the file exits but not enough is continue Y/N").strip()
            if chocie.upper()=="Y":
                self.socket.sendall("Y").encode("utf-8")
                continue_poslite=self.socket.recv(1024).decode("utf-8")
                has_sent +=int(continue_poslite)
                f = open(local_ptah,'rb')
                f.seek(has_sent)
                data =f.read(1024)
                self.socket.sendall(data).encode("utf-8")

            else:
                self.socket.sendall("N").encode("utf-8")
        elif is_exits=="801":
            '''文件完全存在'''
            return
        else:
            pass

        f = open(local_ptah,'rb')
        md5_obj = hashlib.md5()
        while has_sent<file_size:
            data = f.read(1024)
            self.socket.sendall(data)
            has_sent += len(data)
            md5_obj.update(data)
            self.show_progress(has_sent,file_size)
        f.close()
        print("上传成功")
        md5_val= md5_obj.hexdigest()
        self.socket.sendall(md5_val.encode("utf-8")) # 文件一致性校验

    def show_progress(self,has,total):
        rate = float(has)/float(total)
        rata_num = int(rate*100)
        sys.stdout.write("%s %% %s\r" %(rata_num,+ "#"*rata_num))

    def get(self,*cmd_list):
        pass

    def ls(self,*cmd_list):

        data={"action":"ls",
              }
        self.socket.sendall(json.dumps(data).encode("utf-8"))
        data = self.socket.recv(1024).decode("utf-8")
        print(data)

    def cd(self,*cmd_list):
        data = {"action": "cd",
                "dirname":cmd_list[1],
                }
        self.socket.sendall(json.dumps(data).encode("utf-8"))
        data = self.socket.recv(1024).decode("utf-8")
        self.current_dir = os.path.basename(data)
        print(data)

    def makedir(self,*cmd_list):
        data = {"action": "makedir",
                "dirname": cmd_list[1],
                }
        self.socket.sendall(json.dumps(data).encode("utf-8"))
        data = self.socket.recv(1024).decode("utf-8")
        print(data)


    def authenticate(self):
        '''认证功能'''
        if self.options.username is None or self.options.password is None:
            username = input("username: ").strip()
            password = input("password: ").strip()
            return self.get_auth_result(username,password)
        return self.get_auth_result(self.options.username,self.options.password)

    def response(self):
        data = self.socket.recv(1024).decode('utf-8')
        data = json.loads(data)
        return data

    def get_auth_result(self,user,pwd):
        data ={"action":"auth",
               "username":user,
               "password":pwd
               }
        self.socket.sendall(json.dumps(data).encode("utf-8"))
        response = self.response()
        print(response['status_code'])

        if response['status_code']==254:
            self.user = user
            self.current_dir=user
            print(STATUS_CODE["254"])
            return True
        else:
            print(response['status_code'])

ch = ClientHandler()
ch.interactive()